using UnityEngine;
using System.Text;
using LuaInterface;
using UnityEngine.SceneManagement;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System;
using System.Text.RegularExpressions;
using UObject = UnityEngine.Object;
using System.Security.Cryptography;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using UnityEngine.UI;


namespace CardEHT
{
    public class YXUtility
    {
        public static string[] StringListEmpty = new string[] { };

        public static GameObject NewGameObject(string name, GameObject parent = null)
        {
            GameObject go = new GameObject();
            if (parent != null)
            {
                go.transform.SetParent(parent.transform);
            }
            go.transform.name = name;
            go.transform.position = Vector3.zero;
            go.transform.localScale = Vector3.one;
            go.transform.localPosition = Vector3.zero;
            go.transform.localRotation = Quaternion.identity;
            return go;
        }
        public static GameObject CloneGameObject(GameObject goOrigin, GameObject parent = null)
        {
            GameObject goClone = null;
            if (goOrigin != null)
            {
                goClone = GameObject.Instantiate(goOrigin);
            }
            else
            {
                goClone = new GameObject();
                goOrigin = goClone;
            }
            goClone.name = goOrigin.name;
            if (parent != null)
            {
                goClone.transform.SetParent(parent.transform);
            }
            goClone.transform.position = goOrigin.transform.position;
            goClone.transform.localScale = goOrigin.transform.localScale;
            goClone.transform.localPosition = goOrigin.transform.localPosition;
            goClone.transform.localRotation = goOrigin.transform.localRotation;
            return goClone;
        }
        public static void Destroy(UObject uo)
        {
            if (uo == null) return;
#if UNITY_EDITOR
            GameObject.DestroyImmediate(uo);
#else
            GameObject.Destroy(uo);
#endif
        }
        public static void DestroyImmediate(GameObject go)
        {
            GameObject.DestroyImmediate(go);
        }
        public static void DestroyAllChildImmediate(GameObject go)
        {
            int cnt, i;
            cnt = go.transform.childCount;
            for (i = 0; i < cnt; i++)
            {
                DestroyImmediate(go.transform.GetChild(0).gameObject);
            }
        }
        public static void DestroyAllChild(GameObject go, bool bWithRoot = false)
        {
#if UNITY_EDITOR
            int cnt, i;
            cnt = go.transform.childCount;
            if (Application.isPlaying)
            {
                for (i = 0; i < cnt; i++)
                {
                    GameObject.Destroy(go.transform.GetChild(i).gameObject);
                }
                if (bWithRoot) GameObject.Destroy(go);
            }
            else
            {
                for (i = 0; i < cnt; i++)
                {
                    GameObject.DestroyImmediate(go.transform.GetChild(0).gameObject);
                }
                if (bWithRoot) GameObject.DestroyImmediate(go);
            }
#else
            int cnt, i;
            cnt = go.transform.childCount;
            for (i = 0; i < cnt; i++) {
                GameObject.Destroy(go.transform.GetChild(i).gameObject);
            }
            if (bWithRoot) GameObject.Destroy(go);
#endif
        }

        // ---------------------------------------------------------------------------------------
        public static float LogTimeBegin()
        {
            return Time.realtimeSinceStartup;
        }
        public static void LogTimeEnd(float t1, string msg, string title)
        {
            YXLog.LogWarning(string.Format("{0} | {1} | {2}", msg, title, (Time.realtimeSinceStartup - t1)));
        }

        private static long _time1970ticks = new DateTime(1970, 1, 1, 0, 0, 0).Ticks;

        public static string RandomTime()
        {
            return DateTime.Now.ToString("yyyyMMddHHmmss");
        }

        public static float GetRealtimeSinceStartup()
        {
            return Time.realtimeSinceStartup;
        }

        public static long GetTime()
        {
            TimeSpan ts = new TimeSpan(DateTime.UtcNow.Ticks - _time1970ticks);
            return (long)ts.TotalMilliseconds;
        }
        public static float GetTimeSeconds()
        {
            TimeSpan ts = new TimeSpan(DateTime.UtcNow.Ticks - _time1970ticks);
            return (float)ts.TotalSeconds;
        }


        public static int Random(int min, int max)
        {
            return UnityEngine.Random.Range(min, max);
        }
        public static float Random(float min, float max)
        {
            return UnityEngine.Random.Range(min, max);
        }

        public static void InitRandom(int seed)
        {
            UnityEngine.Random.InitState(seed);
        }

        // -------------------------------------------------------------------------------------------        
        public static string FormatBytesToString(long byteSize)
        {
            if (byteSize <= 0)
            {
                return " 0k";
            }
            StringBuilder sb = new StringBuilder("");
            int g = (int)Mathf.Floor(byteSize / 1073741824);
            long last = byteSize % 1073741824;
            if (g > 0)
            {
                sb.Append(g);
                sb.Append("g ");
            }
            int m = (int)Mathf.Floor(last / 1048576);
            last = last % 1048576;
            if (m > 0)
            {
                sb.Append(m);
                sb.Append("m ");
            }
            int k = (int)Mathf.Floor(last / 1024);
            last = last % 1024;
            if (k > 0)
            {
                sb.Append(k);
                sb.Append("k ");
            }
            int b = (int)last;
            if (b > 0)
            {
                sb.Append(b);
                sb.Append("bytes ");
            }
            return sb.ToString();
        }
        // -------------------------------------------------------------------------------------------        
        public static void ClearConsole()
        {
            var logEntries = System.Type.GetType("UnityEditorInternal.LogEntries,UnityEditor.dll");
            if (logEntries != null)
            {
                var clearMethod = logEntries.GetMethod("Clear", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public);
                clearMethod.Invoke(null, null);
            }
        }

        // -------------------------------------------------------------------------------------
        public static uint MakeKey32(ushort v1, ushort v2)
        {
            uint key = v1;
            return (key << 16) | v2;
        }
        public static ushort GetKey32First(uint key)
        {
            return (ushort)((key & 0xFFFF0000) >> 16);
        }
        public static ushort GetKey32Next(uint key)
        {
            return (ushort)(key & 0x0000FFFF);
        }
        public static void GetKey32(uint key, ref int v1, ref int v2)
        {
            v1 = (int)((key & 0xFFFF0000) >> 16);
            v2 = (int)(key & 0x0000FFFF);
        }
        public static ulong MakeKey64(uint v1, uint v2)
        {
            ulong key = v1;
            return ((key << 32) | v2);
        }
        public static uint GetKey64First(ulong key)
        {
            return (uint)((key & 0xFFFFFFFF00000000) >> 32);
        }
        public static uint GetKey64Next(ulong key)
        {
            return (uint)(key & 0x00000000FFFFFFFF);
        }
        public static void GetKey64(ulong key, ref uint v1, ref uint v2)
        {
            v1 = (uint)((key & 0xFFFFFFFF00000000) >> 32);
            v2 = (uint)(key & 0x00000000FFFFFFFF);
        }

        public static bool IsInAndroidApkPath(string path)
        {
            return path.StartsWith(AppConst.AndroidApkKeyHead);
        }

        public static bool IsVirtualStreamassetPath()
        {
            if (Application.platform == RuntimePlatform.WebGLPlayer)
            {
                return true;
            }
            return false;
        }

        static List<string> _EmojiPatterns = new List<string>
        {
            @"\p{Cs}",
            @"\p{Co}",
            @"\p{Cn}",
            @"[\u2702-\u27B0]",
        };
        public static string FilterEmoji(string srcStr, string filterStr)
        {
            if (string.IsNullOrEmpty(srcStr))
            {
                return srcStr;
            }

            if (string.IsNullOrEmpty(filterStr))
            {
                return srcStr;
            }
            for (int i = 0; i < _EmojiPatterns.Count; i++)
            {
                srcStr = Regex.Replace(srcStr, _EmojiPatterns[i], filterStr);
            }
            return srcStr;
        }

        public static bool CopyStrToSystemClipboard(string str)
        {
            if (string.IsNullOrEmpty(str)) return false;
            GUIUtility.systemCopyBuffer = str;
            return true;
        }

        public static string Base64Decode(string content)
        {
            byte[] conentbytes = Convert.FromBase64String(content);
            string result = Encoding.UTF8.GetString(conentbytes);
            return result;
        }

        public static string Base64Decode(byte[] bytes)
        {
            string content = Encoding.UTF8.GetString(bytes);
            byte[] conentbytes = Convert.FromBase64String(content);
            string result = Encoding.UTF8.GetString(conentbytes);
            return result;
        }

        public static string Base64Encode(string content)
        {
            byte[] conentbytes = Encoding.UTF8.GetBytes(content);
            string result = Convert.ToBase64String(conentbytes);
            return result;
        }
        public static byte[] Base64DecodeToBytes(string content)
        {
            byte[] conentbytes = Convert.FromBase64String(content);
            return conentbytes;
        }

        public static string Base64EncodeBytes(byte[] conentbytes)
        {
            string result = Convert.ToBase64String(conentbytes);
            return result;
        }

        public static string XORDecode(byte[] content, string cryptKey)
        {
            byte[] conentbytes = content;
            char[] arr = cryptKey.ToCharArray();
            int index = 0;
            int keyLen = arr.Length;
            int byteLen = conentbytes.Length;
            for (int i = 0; i < byteLen; i++)
            {
                conentbytes[i] = (byte)((conentbytes[i] ^ arr[index]) & 0xff);
                index++;
                if (index >= keyLen)
                {
                    index = 0;
                }
            }
            return Encoding.UTF8.GetString(conentbytes);
        }

        public static byte[] XOREncode(string content, string cryptKey)
        {
            byte[] conentbytes = Encoding.UTF8.GetBytes(content);
            char[] arr = cryptKey.ToCharArray();
            int index = 0;
            int keyLen = arr.Length;
            int byteLen = conentbytes.Length;
            for (int i = 0; i < byteLen; i++)
            {
                conentbytes[i] = (byte)((conentbytes[i] ^ arr[index]) & 0xff);
                index++;
                if (index >= keyLen)
                {
                    index = 0;
                }
            }
            return conentbytes;
        }


        public static bool ReadCryptKeyWordFile(string path, string cryptKey, bool bCheckMd5, bool bDecode, out string result)
        {
            result = "";
            if (!YXFileUtil.FileExists(path)) return false;
            try
            {
                byte[] bytesEncode = YXFileUtil.FileReadBytes(path);
                bool ret = DecodeCryptKeyword(bytesEncode, cryptKey, bCheckMd5, bDecode, out result);
                return ret;
            }
            catch
            {

            }
            return false;
        }

        public static string GetCryptRandomString()
        {
            byte[] randomBytes = new byte[4];
            RNGCryptoServiceProvider rngServiceProvider = new RNGCryptoServiceProvider();
            rngServiceProvider.GetBytes(randomBytes);
            int result = BitConverter.ToInt32(randomBytes, 0);
            return result.ToString();
        }

        public static string Sha256HMAC(string key, string content)
        {
            var encoding = new System.Text.UTF8Encoding();
            byte[] keyByte = encoding.GetBytes(key);
            byte[] contentByte = encoding.GetBytes(content);
            using (var hmacsha256 = new HMACSHA256(keyByte))
            {
                byte[] hashMesg = hmacsha256.ComputeHash(contentByte);
                int length = hashMesg.Length;
                byte[] hexChars = new byte[length * 2];
                for (int i = 0; i < hashMesg.Length; i++)
                {
                    string s = string.Format("{0:x2}", hashMesg[i] & 0xff);
                    byte[] temp = encoding.GetBytes(s);
                    hexChars[i * 2] = temp[0];
                    hexChars[i * 2 + 1] = temp[1];
                }
                return encoding.GetString(hexChars);
            }
        }
        public static string GetSha256Sign(string keyFormat, string ak, string sk, string data, int expiration, long timestamp)
        {
            string signKeyInfo = string.Format(keyFormat, ak, timestamp, expiration);
            string signKey = Sha256HMAC(sk, signKeyInfo);
            string signResult = Sha256HMAC(signKey, data);
            return signResult;
        }

        public static bool WriteFileWithEndocde(string filepath, string content, int encodeType, string cryptKey)
        {
            try
            {
                YXFileUtil.DirectoryCreate(Path.GetDirectoryName(filepath));
                if (File.Exists(filepath)) File.Delete(filepath);
                if (encodeType == 1)
                {
                    byte[] bytes = XOREncode(content, cryptKey);
                    File.WriteAllBytes(filepath, bytes);
                }
                else
                {
                    File.WriteAllText(filepath, Base64Encode(content));
                }

                return true;
            }
            catch (Exception e)
            {
                YXLog.LogError(e.Message, e.StackTrace);
            }
            return false;
        }

        public static bool ReadFileWithEndocde(string filepath, int decodeType, string cryptKey, out string result)
        {
            result = "";
            if (!YXFileUtil.FileExists(filepath)) return false;
            try
            {
                if (decodeType == 1)
                {
                    byte[] bytesEncode = YXFileUtil.FileReadBytes(filepath);
                    result = XORDecode(bytesEncode, cryptKey);
                }
                else
                {
                    result = Base64Decode(YXFileUtil.FileReadText(filepath));
                }
                return true;
            }
            catch
            {

            }
            return false;
        }

        public static bool DecodeCryptKeyword(byte[] bytesEncode, string cryptKey, bool bCheckMd5, bool bDecode, out string result)
        {
            result = "";
            try
            {
                char[] arr = cryptKey.ToCharArray();
                int len = bytesEncode.Length;
                if (len <= 36)
                {
                    return false;
                }

                int mod = (len - 36) % 32;
                int index = 0;
                int keyLen = arr.Length;
                for (int i = 36; i < len; i += mod)
                {
                    bytesEncode[i] = (byte)((bytesEncode[i] ^ arr[index]) & 0xff);
                    index++;
                    if (index >= keyLen)
                    {
                        index = 0;
                    }
                }

                result = Encoding.UTF8.GetString(bytesEncode, 36, len - 36);

                if (bCheckMd5)
                {
                    string filemd5 = Encoding.UTF8.GetString(bytesEncode, 0, 32);
                    string cmpMd5 = YXMd5.md5FromString(result);
                    if (!filemd5.Equals(cmpMd5, StringComparison.OrdinalIgnoreCase))
                    {
                        return false;
                    }
                }

                if (bDecode)
                {
                    result = Base64Decode(result);
                }

                return true;
            }
            catch
            {

            }
            return false;
        }

        public static byte[] Compress(byte[] bytes, int method = 0)
        {
            if (method == 1)
            {
                return Ionic.Zlib.GZipStream.CompressBuffer(bytes);
            }
            else
            {
                return Ionic.Zlib.ZlibStream.CompressBuffer(bytes);
            }


        }
        public static byte[] Decompress(byte[] bytes, int method = 0)
        {
            if (method == 1)
            {
                return Ionic.Zlib.GZipStream.UncompressBuffer(bytes);
            }
            else
            {
                return Ionic.Zlib.ZlibStream.UncompressBuffer(bytes);
            }
        }

        public static short ReverseEndians(short n)
        {
            return (short)(((n & 0xff) << 8) | ((n >> 8) & 0xff));
        }
        public static ushort ReverseEndians(ushort n)
        {
            return (ushort)(((n & 0xff) << 8) | ((n >> 8) & 0xff));
        }
        public static int ReverseEndians(int n)
        {
            return ((ReverseEndians((short)n) & 0xffff) << 0x10) | (ReverseEndians((short)(n >> 0x10)) & 0xffff);
        }
        public static uint ReverseEndians(uint n)
        {
            return (uint)(((ReverseEndians((ushort)n) & 0xffff) << 0x10) | (ReverseEndians((ushort)(n >> 0x10)) & 0xffff));
        }
        public static int ReverseEndians(byte[] buffer, int n)
        {
            return ((buffer[0] & 0xff) << 24) | ((buffer[1] & 0xff) << 16) | ((buffer[2] & 0xff) << 8) | ((buffer[3] & 0xff));
        }
        public static long ReverseEndians(long n)
        {
            return ((ReverseEndians((int)n) & 0xffffffffL) << 0x20) | (ReverseEndians((int)(n >> 0x20)) & 0xffffffffL);
        }
        public static ulong ReverseEndians(ulong n)
        {
            return (ulong)(((ReverseEndians((uint)n) & 0xffffffffL) << 0x20) | (ReverseEndians((uint)(n >> 0x20)) & 0xffffffffL));
        }

        public static string GetIPAddress()
        {
            string ipAddress = "";
#if !UNITY_WEBGL
            foreach (NetworkInterface item in NetworkInterface.GetAllNetworkInterfaces())
            {
#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
                NetworkInterfaceType _type1 = NetworkInterfaceType.Wireless80211;
                NetworkInterfaceType _type2 = NetworkInterfaceType.Ethernet;

                if ((item.NetworkInterfaceType == _type1 || item.NetworkInterfaceType == _type2) && item.OperationalStatus == OperationalStatus.Up)
#endif
                {
                    foreach (UnicastIPAddressInformation ip in item.GetIPProperties().UnicastAddresses)
                    {
                        //IPv4
                        if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
                        {
                            ipAddress = ip.Address.ToString();
                        }

                        //IPv6
                        if (Socket.OSSupportsIPv6 && string.IsNullOrEmpty(ipAddress))
                        {
                            if (ip.Address.AddressFamily == AddressFamily.InterNetworkV6)
                            {
                                ipAddress = ip.Address.ToString();
                            }
                        }
                    }
                }
            }
#endif
            return ipAddress;
        }

        public static string DeserializeServerData(string base64Str, string key)
        {
            //解压数据
            byte[] bytes = Convert.FromBase64String(base64Str);
            int len = bytes.Length;
            int sidx = Mathf.FloorToInt((len - len % 2) / 2);
            int eidx = sidx + 20;
            var keyBytes = Encoding.UTF8.GetBytes(key);
            var encryptBytes = DecryptToByte(bytes, keyBytes, sidx, eidx);
            encryptBytes = Decompress(encryptBytes, 1);
            var str = Encoding.UTF8.GetString(encryptBytes);
            return str;
        }

        /// <summary>
        /// Base64编码
        /// </summary>
        public static string EncodeBase64(string message)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(message);
            return Convert.ToBase64String(bytes);
        }

        public static string EncodeByteToBase64(byte[] bytes)
        {
            return Convert.ToBase64String(bytes);
        }

        /// <summary>
        /// Base64解码
        /// </summary>
        public static string DecodeBase64(string message)
        {
            byte[] bytes = Convert.FromBase64String(message);
            return Encoding.UTF8.GetString(bytes);
        }

        public static byte[] DecodeBase64ToByte(string message)
        {
            byte[] bytes = Convert.FromBase64String(message);
            return bytes;
        }

        static byte[] _SimpleKeys = { 0x58, 0x55, 0x62, 0x65, 0x64, 0x65, 0x56 };//"X E R U T U F"

        /// <summary>
        /// 简单加密
        /// </summary>
        public static byte[] Encrypt(string message)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(message);
            return Encrypt(bytes, _SimpleKeys);
        }

        public static byte[] Encrypt(byte[] bytes, byte[] keys, int sidx = 0, int eidx = -1, int step = 1)
        {
            int cnt = bytes.Length;
            int kLen = keys.Length;

            if (eidx > 0 && eidx < cnt)
            {
                cnt = eidx;
            }
            if (sidx >= cnt)
            {
                sidx = cnt - 1;
            }

            int kIdx = 0;
            for (int k = sidx; k < cnt; k += step)
            {
                bytes[k] ^= _SimpleKeys[kIdx];
                kIdx++;
                if (kIdx >= kLen) kIdx = 0;

            }
            return bytes;
        }

        public static byte[] DecryptToByte(byte[] bytes)
        {
            return DecryptToByte(bytes, _SimpleKeys);
        }

        /// <summary>
        /// 简单解密
        /// </summary>
        public static byte[] DecryptToByte(byte[] bytes, byte[] keys, int sidx = 0, int eidx = -1, int step = 1)
        {
            int cnt = bytes.Length;
            if (eidx > 0 && eidx < cnt)
            {
                cnt = eidx;
            }
            if (sidx >= cnt)
            {
                sidx = cnt - 1;
            }
            int kLen = keys.Length;
            int kIdx = sidx % kLen;
            for (int k = sidx; k < cnt; k += step)
            {
                bytes[k] ^= keys[kIdx];
                kIdx++;
                if (kIdx >= kLen) kIdx = 0;
            }
            return bytes;
        }

        public static string Decrypt(byte[] bytes)
        {
            return Decrypt(bytes, _SimpleKeys);
        }

        /// <summary>
        /// 简单解密
        /// </summary>
        public static string Decrypt(byte[] bytes, byte[] keys, int sidx = 0, int eidx = -1, int step = 1)
        {
            return Encoding.UTF8.GetString(DecryptToByte(bytes, keys, sidx, eidx, step));
        }
        
        public static void UnloadAsset(GameObject gameObj)
        {
            if (gameObj != null)
            {
                UnloadAssetType<Text>(gameObj);
                UnloadAssetType<Image>(gameObj);
            }
        }

        static void UnloadAssetType<T>(GameObject gameObj)
        {
            var components = gameObj.GetComponentsInChildren<T>();
            if (components.Length > 0)
            {
                Type compType = typeof(T);
                var assets = new List<UnityEngine.Object>();
                for (int i = 0; i < components.Length; i++)
                {
                    var c = components[i];
                    if (compType == typeof(Image))
                    {
                        var textImage = c as YXTextureImage;

                        var image = c as Image;
                        if (textImage == null && image != null && image.sprite != null && !assets.Contains(image.sprite.texture))
                        {
                            assets.Add(image.sprite.texture);
                        }
                    }
                    else if (compType == typeof(Text))
                    {
                        var text = c as Text;
                        if (text != null && !assets.Contains(text.font))
                        {
                            assets.Add(text.font);
                        }
                    }
                }
                for (int i = 0; i < assets.Count; i++)
                {
                    if (assets[i] != null)
                    {
                        UnityEngine.Debug.Log("  =---> " + i + " | name=" + assets[i].name);
                        Resources.UnloadAsset(assets[i]);
                    }
                }
                assets = null;
            }
        }


    }

}

